extern "C"
{
#include <errno.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <string.h>
}
#include <sstream>

#include "server.h"
#include "logger.h"
#include "socket.h"
#include "concurrent/thread.hpp"
#include "wsgi/middleware.hpp"

namespace night_sky
{
  DefaultServer::DefaultServer(const int port, wsgi::Middleware* ware)
    : logger(Logger::getInstance()),
      m_port(port),
      m_isStopped(false),
      m_pMiddleware(ware)
  {}

  DefaultServer::~DefaultServer()
  {
    this->stop(); // Status は無視
    if (this->m_pMiddleware != NULL) {
      // TODO thread との絡み
      delete this->m_pMiddleware;
      this->m_pMiddleware = NULL;
    }
  }

  Server::Status DefaultServer::start()
  {
    return this->start(this->m_port);
  }

  Server::Status DefaultServer::start(const int port)
  {
    if (port < 0) {
      NS_LOGGER_ERROR_2(logger, "illegal port number :", port);
      return Server::FAILURE;
    }

    // サーバソケット作成
    ServerSocket* const socket = createServerSocket(port);
    if (socket == NULL) {
      NS_LOGGER_ERROR_3(logger, "failed creating socket (port=", port, ")");
      return Server::FAILURE;
    }
    NS_LOGGER_INFO_1(logger, "server ready...");
    this->m_isStopped = false;

    // アクセプト開始
    doAccept(*socket);

    // 受付終了したので閉じる
    delete socket;
    return Server::SUCCESS;
  }

  Server::Status DefaultServer::stop()
  {
    if(this->isStopped())
    {
      return Server::SUCCESS;
    }
    // TODO
    this->m_isStopped = true;
    return Server::SUCCESS;
  }

  ServerSocket* DefaultServer::createServerSocket(const int port) const
  {
    ServerSocket* socket = new ServerSocket();
    if (!socket->init()) {
      return NULL;
    }
    if (!socket->bind(port)) {
      return NULL;
    }
    if (!socket->listen(SOMAXCONN)) {
      return NULL;
    }
    NS_LOGGER_INFO_3(logger, "listen (port=", port, ")");
    return socket;
  }

  class ConnectionContext {
  private:
    AcceptedSocket* psocket;
    wsgi::Middleware* pmiddleware;

  public:
    ConnectionContext(AcceptedSocket* psoc, wsgi::Middleware* pware)
      : psocket(psoc), pmiddleware(pware)
    {}
    ~ConnectionContext() {
      if (this->psocket != NULL) {
        delete this->psocket; this->psocket = NULL;
      }
      // Middleware は Server の持ち物
    }

    const AcceptedSocket& socket() const {
      return *this->psocket;
    }
    bool hasMiddleware() const {
      return this->pmiddleware != NULL;
    }
    wsgi::Middleware& middleware() {
      return *this->pmiddleware;
    }
  };

  class ConnectionThread : public concurrent::Thread {
  public:
    ConnectionThread(func_type f, ConnectionContext* context)
      : Thread(f, context)
    {}
    ~ConnectionThread() {
      if (this->get_arg_ptr() != NULL) {
        ConnectionContext* p = (ConnectionContext*)(this->release_arg_ptr());
        delete p;
        printf("[Debug] delete context on destructor\n");
      }
    }
  };

  void* g_loop_send_recv(void* arg) {
    ConnectionContext& context = *((ConnectionContext*)arg); 
    const AcceptedSocket& socket = context.socket();
    while (1) {
      std::string msg = socket.recvUntil("\n");
      if (msg.empty()) {
        break;
      }

      // XXX temporary
      if (context.hasMiddleware()) {
        wsgi::Environment env;
        env.set("tcp.data", msg);
        msg = context.middleware().call(env);
      }

      // 返事
      if (!socket.send(msg + ", OK\n")) {
        break;
      }
    }
    return NULL;
  }

  // アクセプトループ
  void DefaultServer::doAccept(const ServerSocket& socket) const {
    while (1) {
      AcceptedSocket* accepted = socket.accept();
      if (accepted != NULL) {
        const struct sockaddr_in& from = accepted->getSockAddrIn();
        NS_LOGGER_INFO_4(logger,
            "accept: ", inet_ntoa(from.sin_addr), ":", ntohs(from.sin_port));

        // 送受信ループ
        ConnectionContext* context = new ConnectionContext(accepted, this->m_pMiddleware);
        accepted = NULL;
        (new ConnectionThread(g_loop_send_recv, context))->start();
      }
    }
  }

  void DefaultServer::loop_send_recv(const AcceptedSocket& socket) const {
    while (1) {
      const std::string msg = socket.recvUntil("\n");
      if (msg.empty()) {
        if (errno != 0) {
          NS_LOGGER_WARN_2(logger, "recv error: ", strerror(errno));
        } else {
          NS_LOGGER_INFO_1(logger, "recv: EOF");
        }
        break;
      }

      NS_LOGGER_INFO_5(logger, "from client: ", msg, "(len=", msg.length(), ")");

      // 返事
      if (!socket.send(msg + ", OK\n")) {
        break;
      }
    }
  }

}// namespace night_sky
